using System;
using System.Collections.Generic;

namespace CGF
{
    public class UIManagerComponent : ComponentBase, IAwake, IDestroy
    {
        public static UIManagerComponent instance { get; private set; }

        private Dictionary<UILayer, List<UIComponentBase>> uiStacks = new Dictionary<UILayer, List<UIComponentBase>>();
        private Dictionary<Type, ComponentBase> uiParents = new Dictionary<Type, ComponentBase>();

        public void Awake()
        {
            instance = this;
        }

        /// <summary>
        /// 当调用一个UI组件的Open()方法时，前一个UI无需调用Close()，UI管理器会将所有UI入栈管理，只有栈顶的UI才会显示，其余都会自动关闭。
        /// 关闭当前栈顶UI只需执行Close()方法即可，无需调用之前UI的Open()，栈顶UI移除后被推来的新UI会自动显示。
        /// 当传入isFloat=true时，前一个UI不会隐藏。
        /// 栈内的任何UI被主动调用Close()或者Dispose()后，会立即从栈内移除，不再参与该策略。
        /// </summary>
        public T OpenUI<T>(UILayer layer, ComponentBase parentComponent, bool isFloat) where T : UIComponentBase, IAwake<UILayer, bool>, new()
        {
            if (parentComponent == null)
            {
                LogError($"传入的 parentComponent 为空");
                return default(T);
            }

            List<UIComponentBase> uiStack = null;
            if (uiStacks.ContainsKey(layer))
            {
                uiStack = uiStacks[layer];
            }
            else
            {
                uiStack = new List<UIComponentBase>();
                uiStacks.Add(layer, uiStack);
            }
            //先从栈内查找，有则直接移到栈顶显示
            for (int i = uiStack.Count - 1; i >= 0; i--)
            {
                UIComponentBase oldUI = uiStack[i];
                if (oldUI.GetType() == typeof(T))
                {
                    if (i < uiStack.Count - 1)
                    {
                        uiStack.RemoveAt(i);
                        uiStack.Add(oldUI);
                    }
                    //找到已存在的UI，刷新一下顺序和Sorting层级
                    for (int j = 0; j < uiStack.Count; j++)
                    {
                        if (j >= i)
                        {
                            UIComponentBase _ui = uiStack[j];
                            _ui.rectTransform.SetSiblingIndex(j);
                            UISortingComponent sorting = _ui.GetComponent<UISortingComponent>();
                            sorting.RefreshSorting();
                        }
                    }
                    RefreshVisible(layer);
                    return oldUI as T;
                }
            }

            if (uiParents.ContainsKey(typeof(T)))
            {
                LogError($"{uiParents[typeof(T)].GetType().Name} 上已经存在 {typeof(T).Name} 组件，不能重复挂载");
                return null;
            }

            //没有就创建
            uiParents.Add(typeof(T), parentComponent);
            T ui = parentComponent.AddComponent<T, UILayer, bool>(layer, isFloat);
            ui.OnEnable();
            return ui;
        }

        /// <summary>
        /// 调用该方法后，会立即从栈内移除，不再参与置顶自动显示。
        /// </summary>
        public void CloseUI<T>() where T : UIComponentBase
        {
            if (uiParents.ContainsKey(typeof(T)))
            {
                try
                {
                    ComponentBase parent = uiParents[typeof(T)];
                    parent.RemoveComponent<T>();
                    uiParents.Remove(typeof(T));
                }
                catch (Exception ex)
                {
                    LogError(ex);
                }
            }
        }

        public void OnUIComponentRemove(UIComponentBase ui)
        {
            if (uiStacks.ContainsKey(ui.layer))
            {
                List<UIComponentBase> uiStack = uiStacks[ui.layer];
                if (uiStack.Contains(ui))
                {
                    uiStack.Remove(ui);
                    RefreshVisible(ui.layer);
                }
            }
            if (uiParents.ContainsKey(ui.GetType()))
            {
                uiParents.Remove(ui.GetType());
            }
        }

        public void OnUICreate(UIComponentBase ui, UILayer layer)
        {
            List<UIComponentBase> uiStack = null;
            if (uiStacks.ContainsKey(layer))
            {
                uiStack = uiStacks[layer];
            }
            else
            {
                uiStack = new List<UIComponentBase>();
                uiStacks.Add(layer, uiStack);
            }
            uiStack.Add(ui);
            RefreshVisible(layer);
        }

        private void RefreshVisible(UILayer layer)
        {
            //栈顶才显示，其他隐藏，如果栈顶是浮动UI(isFloat=true)，则临近的下层也显示
            if (uiStacks.ContainsKey(layer))
            {
                List<UIComponentBase> uiStack = uiStacks[layer];
                bool haveFullScreen = false;
                for (int i = uiStack.Count - 1; i >= 0; i--)
                {
                    UIComponentBase attr = uiStack[i];
                    if (i == uiStack.Count - 1)
                    {
                        //栈顶必须显示
                        attr._SetUIVisible(true);
                        if (!attr.gameObject.activeSelf) attr.gameObject.SetActive(true);
                    }
                    else
                    {
                        if (haveFullScreen)
                        {
                            //只要上层有一层UI全屏，底层一律全部隐藏
                            attr._SetUIVisible(false);
                            if (attr.gameObject.activeSelf) attr.gameObject.SetActive(false);
                        }
                        else
                        {
                            //顶层为浮动层的，临近下一层要显示
                            UIComponentBase aboveAttr = uiStack[i + 1];
                            bool show = aboveAttr.isFloat;
                            attr._SetUIVisible(show);
                            if (attr.gameObject.activeSelf != show) attr.gameObject.SetActive(show);
                        }
                    }
                    if (!haveFullScreen && !attr.isFloat) haveFullScreen = true;
                }
            }
        }

        public void OnDestroy()
        {
            instance = null;
        }
    }
}
